package gamesyslogic

import (
	"context"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go.uber.org/zap"
	gameuserlogic "navi-mumbai/app/rpc/game/internal/logic/gameuser"
	"navi-mumbai/app/rpc/game/internal/svc"
	"navi-mumbai/app/rpc/game/pb"
	"navi-mumbai/app/rpc/model/pg/game"
	"navi-mumbai/common/key/dbkey"
	"navi-mumbai/common/key/gamekey"
	"navi-mumbai/common/key/walletkey"
	"navi-mumbai/common/utils"
	"navi-mumbai/common/xerr"
	"navi-mumbai/third/game/wz"
	"strconv"
	"time"

	"github.com/zeromicro/go-zero/core/logx"
)

type PullGameOrderLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewPullGameOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PullGameOrderLogic {
	return &PullGameOrderLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// 定时拉取game order
func (l *PullGameOrderLogic) PullGameOrder(in *pb.PullGameOrderReq) (*pb.PullGameOrderResp, error) {
	defer utils.RecoverPanic()

	var startId int64 = 0
	var err error
	if in.StartIdx > 0 {
		startId = in.StartIdx
	} else {
		var orderStat *game.OrderStat
		orderStat, err = l.svcCtx.OrderStatModel.FindOne(l.ctx, in.ProviderId)
		if err != nil && err != game.ErrNotFound {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		if orderStat != nil {
			startId = orderStat.LastIdx
		} else {
			orderStat = new(game.OrderStat)
			orderStat.ProviderId = in.ProviderId
			orderStat.LastIdx = 0
			_, err = l.svcCtx.OrderStatModel.Insert(l.ctx, orderStat)
			if err != nil {
				l.Logger.Errorf("err == ", zap.Error(err))
				return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
			}
		}
	}

	// 拉取订单
	var queryOrderReq wz.QueryOrderReq
	queryOrderReq.Last = startId
	queryOrderReq.Per = in.Size
	var queryOrderResp *wz.QueryOrderResp
	queryOrderResp, err = wz.Hc.QueryOrder(&queryOrderReq)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}

	//
	var resp pb.PullGameOrderResp
	resp.NextIdx = queryOrderResp.Data.Last
	resp.Count = queryOrderResp.Data.Count
	resp.List = make([]*pb.PullGameOrder, 0)

	queryData := queryOrderResp.Data.Data
	if len(queryData) <= 0 {
		return &resp, nil
	}

	if queryOrderResp.Data == nil || len(queryData) <= 0 {
		return &resp, nil
	}
	err = l.svcCtx.GameModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		var rspUid *pb.GetUidByOpenIdResp
		for idx := 0; idx < len(queryData); idx++ {
			order := game.Order1{
				Id:         queryData[idx].BetId,
				RoundId:    queryData[idx].RoundId,
				Username:   queryData[idx].Username,
				CurrencyId: queryData[idx].CurrencyId,
				InstId:     queryData[idx].InstId,
				GameId:     queryData[idx].GameId,
				Currency:   queryData[idx].Currency,
				IsFreeBet:  dbkey.Disable,
				Win:        dbkey.Disable,
				BetAmt:     0,
				WinAmt:     0,
				Payout:     queryData[idx].Payout,
				OpenId:     0,
				Status:     queryData[idx].Status,
				Ver:        queryData[idx].Ver,
				//Details:    queryData[idx].Details,
			}

			if queryData[idx].FreeBet {
				order.IsFreeBet = dbkey.Enable
			}

			//if queryData[idx].Win {
			//	order.Win = dbkey.Enable
			//}

			// TODO 币种兑换比例
			if queryData[idx].BetAmt != "" {
				var dBetAmt decimal.Decimal
				dBetAmt, err = decimal.NewFromString(queryData[idx].BetAmt)
				if err != nil {
					l.Logger.Errorf("err == ", zap.Error(err))
					l.Logger.Errorf("PullGameOrderLogic BetAmt:%s err:%s", queryData[idx].BetAmt, err.Error())
					return xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, err.Error())
				}
				order.BetAmt = dBetAmt.Mul(decimal.NewFromInt(walletkey.MoneyScale)).IntPart()
			}
			if queryData[idx].WinAmt != "" {
				var dWinAmt decimal.Decimal
				dWinAmt, err = decimal.NewFromString(queryData[idx].WinAmt)
				if err != nil {
					l.Logger.Errorf("err == ", zap.Error(err))
					l.Logger.Errorf("PullGameOrderLogic WinAmt:%s err:%s", queryData[idx].WinAmt, err.Error())
					return xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, err.Error())
				}
				order.WinAmt = dWinAmt.Mul(decimal.NewFromInt(walletkey.MoneyScale)).IntPart()
			}

			if queryData[idx].Uid != "" {
				order.OpenId, err = strconv.ParseInt(queryData[idx].Uid, 10, 64)
				if err != nil {
					l.Logger.Errorf("err == ", zap.Error(err))
					l.Logger.Errorf("PullGameOrderLogic Uid:%s err:%s", queryData[idx].Uid, err.Error())
					return xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, err.Error())
				}
			}

			if queryData[idx].BetTime != 0 {
				order.OrderTime = time.UnixMilli(queryData[idx].BetTime)
			}

			if queryData[idx].PayTime != 0 {
				order.PayTime.Time = time.UnixMilli(queryData[idx].PayTime)
				order.PayTime.Valid = true
			}

			_, err2 := l.svcCtx.Order1Model.InsertTrans(ctx, tx, &order)
			if err2 != nil {
				l.Logger.Errorf("err == ", zap.Error(err2))
				l.Logger.Errorf("PullGameOrderLogic InsertTrans err:%s, order:%+v", err2.Error(), queryData[idx])
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
			}

			//
			var pullGameOrder pb.PullGameOrder
			pullGameOrder.ExternalFlowNo = strconv.FormatInt(order.Id, 10)
			// TODO 转换id money type open id status
			// open id 2 uid
			rspUid, err = gameuserlogic.NewGetUidByOpenIdLogic(l.ctx, l.svcCtx).GetUidByOpenId(&pb.GetUidByOpenIdReq{
				OpenId:     strconv.FormatInt(order.OpenId, 10),
				ProviderId: in.ProviderId,
			})
			if err != nil {
				l.Logger.Errorf("err == ", zap.Error(err))
				continue
			}

			// game id
			vG, ok := gamekey.Y9YGameId[order.GameId]
			if ok {
				pullGameOrder.GameId = vG
			} else {
				pullGameOrder.GameId = order.GameId
			}

			pullGameOrder.MoneyType = walletkey.UsingCurrencyType
			pullGameOrder.Uid = rspUid.Uid
			pullGameOrder.State = GetGameOrderState(order.Status)

			pullGameOrder.MoneyAmount = decimal.NewFromInt(order.BetAmt).Div(decimal.NewFromInt(walletkey.MoneyScale)).StringFixedBank(2)
			pullGameOrder.ReturnAmount = decimal.NewFromInt(order.WinAmt).Div(decimal.NewFromInt(walletkey.MoneyScale)).StringFixedBank(2)
			pullGameOrder.OrderTime = order.OrderTime.Format(dbkey.DateTimeCNFormat)
			pullGameOrder.ProviderId = in.ProviderId
			pullGameOrder.Multiplier = order.Payout

			resp.List = append(resp.List, &pullGameOrder)
		}
		_, err2 := l.svcCtx.OrderStatModel.UpdateTrans(ctx, tx, in.ProviderId, queryOrderResp.Data.Last)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		return nil
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}

	return &resp, nil
}

func GetGameOrderState(st int64) int64 {
	switch st {
	case gamekey.GameOrderStateUnknown:
		return 0
	case gamekey.GameOrderStateSuccess:
		return walletkey.GameOrderStateSuccess
	case gamekey.GameOrderStateCancel:
		return walletkey.GameOrderStateCancel
	case gamekey.GameOrderStateInvalid:
		return walletkey.GameOrderStateInvalid
	default:
		return 0
	}
}
